package cn.outsourcing.supermarket.service.impl;

import cn.outsourcing.supermarket.common.PageResult;
import cn.outsourcing.supermarket.common.constants.BackstageGoodsConstants;
import cn.outsourcing.supermarket.common.constants.CommonConstants;
import cn.outsourcing.supermarket.common.exception.SupermarketException;
import cn.outsourcing.supermarket.common.utils.IPageUtils;
import cn.outsourcing.supermarket.common.utils.PageResultUtils;
import cn.outsourcing.supermarket.converter.*;
import cn.outsourcing.supermarket.dto.OnlyIdPayloadDTO;
import cn.outsourcing.supermarket.dto.backstage.*;
import cn.outsourcing.supermarket.mapper.BackstageGoodsMapper;
import cn.outsourcing.supermarket.mapper.HiolabsGoodsMapper;
import cn.outsourcing.supermarket.mapper.HiolabsGoodsSpecificationMapper;
import cn.outsourcing.supermarket.mapper.HiolabsProductMapper;
import cn.outsourcing.supermarket.po.*;
import cn.outsourcing.supermarket.service.*;
import cn.outsourcing.supermarket.vo.ProductSpecificationVO;
import cn.outsourcing.supermarket.vo.backstage.*;
import cn.outsourcing.supermarket.vo.hiolabs.HiolabsGoodsVO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 后台商品服务实现类
 *
 * @author gzkemays
 * @since 2021/11/3 20:04
 */
@Service
public class BackstageGoodsServiceImpl implements BackstageGoodsService {
  @Resource BackstageGoodsMapper backstageGoodsMapper;
  @Resource HiolabsGoodsMapper goodsMapper;
  @Resource HiolabsProductMapper productMapper;
  @Resource HiolabsGoodsSpecificationMapper goodsSpecificationMapper;

  @Resource HiolabsGoodsService goodsService;
  @Resource HiolabsSpecificationService specificationService;
  @Resource HiolabsCategoryService categoryService;
  @Resource HiolabsGoodsGalleryService goodsGalleryService;
  @Resource HiolabsProductService productService;
  @Resource HiolabsGoodsSpecificationService goodsSpecificationService;

  @Override
  public PageResult<BackstageAllGoodsVO> getGoods(
      BackstageGoodsDTO dto, String mode, Integer sort) {
    IPageUtils<HiolabsGoods> properties = IPageUtils.<HiolabsGoods>init().properties(dto);
    IPage<BackstageAllGoodsVO> allGoods =
        backstageGoodsMapper.getAllGoods(properties, dto.getName(), mode, sort);
    List<BackstageAllGoodsVO> records =
        allGoods.getRecords().stream().distinct().collect(Collectors.toList());
    if (CollectionUtils.isEmpty(records)) {
      return PageResultUtils.emptyData();
    }
    String[] idsStr =
        records.stream()
            .map(record -> String.valueOf(record.getId()))
            .distinct()
            .toArray(String[]::new);

    List<ProductSpecificationVO> products =
        productMapper.getProductSpecificationByGoodsId(
            StringUtils.join(idsStr, CommonConstants.COMMA_SEPARATOR));

    for (BackstageAllGoodsVO record : records) {
      List<ProductSpecificationVO> tempProducts = new ArrayList<>();
      for (ProductSpecificationVO product : products) {
        // 将 product 加入 goods.product 当中
        if (product.getGoodsId().equals(record.getId())) {
          tempProducts.add(product);
        }
      }
      record.setProduct(tempProducts);
    }
    return PageResultUtils.parseListPageObjs(properties, records);
  }

  @Override
  public PageResult<BackstageAllGoodsVO> getSortGoods(BackstageGoodsDTO dto, Integer sort) {
    return getGoods(dto, BackstageGoodsConstants.ALL_GOODS, sort);
  }

  @Override
  public BackstageGoodsInfoVO getGoodsInfoById(Integer id) {
    BackstageGoodsInfoVO backstageGoodsInfoVO = new BackstageGoodsInfoVO();
    HiolabsGoodsVO hiolabsGoodsVO =
        HiolabsGoodsConverter.INSTANCE.convertToVo(goodsMapper.selectById(id));
    backstageGoodsInfoVO.setInfo(hiolabsGoodsVO);
    backstageGoodsInfoVO.setCategoryId(hiolabsGoodsVO.getCategoryId());
    return backstageGoodsInfoVO;
  }

  @Override
  public BackstageGalleryVO getGalleryById(BackstageGalleryDTO dto) {
    return new BackstageGalleryVO(
        HiolabsGoodsGalleryConverter.INSTANCE.convertToBackstageGalleryDataVoList(
            goodsGalleryService.getGoodsGallery(dto.getGoodsId())));
  }

  @Override
  public BackstageSpecVO getSpecData(OnlyIdPayloadDTO dto) {
    List<ProductSpecificationVO> productSpecificationVos =
        productMapper.getProductSpecificationByGoodsId(String.valueOf(dto.getId()));
    Integer specificationId = productSpecificationVos.get(0).getSpecificationId();
    return new BackstageSpecVO(
        BackstageGoodsConverter.INSTANCE.convertToEzSpecDataList(productSpecificationVos),
        specificationId);
  }

  @Override
  public List<BackstageSpecificationVO> getAllSpecification() {
    return HiolabsSpecificationConverter.INSTANCE.convertToBackstageVoList(
        specificationService.list());
  }

  @Override
  public List<BackstageEzCategoryVO> getAllCategory() {
    return HiolabsCategoryConverter.INSTANCE.convertToBackstageEzVoList(categoryService.list());
  }

  @Override
  public BackstageExpressDataVO getExpressData() {
    BackstageExpressDataVO backstageExpressDataVO = new BackstageExpressDataVO();
    List<HiolabsCategory> list = categoryService.list();
    List<BackstageEzCategoryVO> cate = new ArrayList<>();
    for (HiolabsCategory category : list) {
      BackstageEzCategoryVO backstageEzCategoryVO = new BackstageEzCategoryVO();
      backstageEzCategoryVO.setLabel(category.getName());
      backstageEzCategoryVO.setValue(category.getId());
      backstageEzCategoryVO.setChildren(new ArrayList<>());
      cate.add(backstageEzCategoryVO);
    }
    backstageExpressDataVO.setCate(cate);
    backstageExpressDataVO.setKd(new ArrayList<>());
    return backstageExpressDataVO;
  }

  @Transactional(rollbackFor = Exception.class)
  @Override
  public int store(BackstageGoodsStoreDTO dto) {
    return saveOrUpdateBackstageStore(dto);
  }

  @Override
  public String indexShowStatus(BackstageUpdateStatusDTO dto) {
    HiolabsGoods goods = new HiolabsGoods();
    goods.setId(dto.getId());
    goods.setIsIndex(dto.getStatus());
    int update = goodsMapper.updateById(goods);
    if (update > 0) {
      return "OK";
    }
    throw new SupermarketException(CommonConstants.SQL_FAIL_CODE, "更新失败");
  }

  @Override
  public String saleStatus(BackstageUpdateStatusDTO dto) {
    HiolabsGoods goods = new HiolabsGoods();
    goods.setId(dto.getId());
    goods.setIsOnSale(dto.getStatus());
    int update = goodsMapper.updateById(goods);
    if (update > 0) {
      return "OK";
    }
    throw new SupermarketException(CommonConstants.SQL_FAIL_CODE, "更新失败");
  }

  @Override
  public boolean checkSku(BackstageCheckSnDTO dto) {
    String goodsSn = dto.getInfo().getGoodsSn();
    boolean isNull =
        productMapper
            .selectList(
                Wrappers.<HiolabsProduct>lambdaQuery().eq(HiolabsProduct::getGoodsSn, goodsSn))
            .isEmpty();
    if (isNull) {
      return true;
    }
    throw new SupermarketException(100, "重复");
  }

  @Override
  public int updateSort(BackstageUpdateSortDTO dto) {
    HiolabsGoods goods = new HiolabsGoods();
    goods.setId(dto.getId());
    goods.setSortOrder(dto.getSort());
    return goodsMapper.updateById(goods);
  }

  @Override
  public int destroy(OnlyIdPayloadDTO dto) {
    HiolabsGoods goods = new HiolabsGoods();
    goods.setId(dto.getId());
    goods.setIsDelete(1);
    return goodsMapper.updateById(goods);
  }

  /**
   * 保存编辑信息
   *
   * @param dto 编辑信息
   * @return 商品 id
   */
  private int saveOrUpdateBackstageStore(BackstageGoodsStoreDTO dto) {
    int i = storeInfo(dto);
    if (i > 0) {
      storeSpec(dto.getSpecData(), dto.getSpecValue(), i);
    }
    return i;
  }

  /**
   * 保存 info
   *
   * <p>画廊以及商品基本信息
   *
   * @param dto info 信息
   * @return 保存结果
   */
  private int storeInfo(BackstageGoodsStoreDTO dto) {
    BackstageGoodsStoreInfoDTO info = dto.getInfo();
    Integer id = info.getId();
    List<BackstageGalleryDataVO> gallery = info.getGallery();
    List<HiolabsGoodsGallery> goodsGalleries =
        HiolabsGoodsGalleryConverter.INSTANCE.convertBackstageToPoList(gallery);
    HiolabsGoods goods = BackstageGoodsConverter.INSTANCE.convertBackstageGoodsStoreInfoToPo(info);

    // 新增商品
    int newId = 0;
    if (Objects.equals(goods.getId(), 0)) {
      // 获取规格列表
      List<BackstageSpecDataVO> specData = dto.getSpecData();
      long stock =
          specData.stream()
              .collect(Collectors.summarizingInt(BackstageSpecDataVO::getGoodsNumber))
              .getSum();
      goods.setGoodsNumber((int) stock);
      List<Integer> sortByRetailPrice =
          specData.stream()
              .sorted(Comparator.comparing(BackstageSpecDataVO::getRetailPrice))
              .map(price -> price.getRetailPrice().intValue())
              .collect(Collectors.toList());
      List<Integer> sortByCost =
          specData.stream()
              .sorted(Comparator.comparing(BackstageSpecDataVO::getCost))
              .map(price -> price.getRetailPrice().intValue())
              .collect(Collectors.toList());

      int minPrice = sortByRetailPrice.get(0);
      goods.setMinRetailPrice(new BigDecimal(minPrice));
      if (sortByRetailPrice.size() > 1) {
        int maxPrice = sortByRetailPrice.get(sortByRetailPrice.size() - 1);
        String retailPrice = minPrice + "~" + maxPrice;
        goods.setRetailPrice(retailPrice);
      } else {
        goods.setRetailPrice(minPrice + "");
      }

      int minCost = sortByCost.get(0);
      goods.setMinCostPrice(new BigDecimal(minCost));
      if (sortByCost.size() > 1) {
        int maxCost = sortByCost.get(sortByCost.size() - 1);
        String cost = maxCost + "~" + minCost;
        goods.setCostPrice(cost);
      } else {
        goods.setCostPrice(minCost + "");
      }

      goods.setId(null);
      goods.setCategoryId(dto.getCateId());
      if (goodsMapper.insert(goods) > 0) {
        newId = goods.getId();
      }
    } else {
      goods.setCategoryId(dto.getCateId());
      goodsMapper.updateById(goods);
    }
    int fnid = newId;
    goodsGalleryService.saveOrUpdateBatch(
        goodsGalleries.stream()
            .peek(g -> g.setGoodsId(fnid == 0 ? id : fnid))
            .collect(Collectors.toList()));
    return fnid == 0 ? id : fnid;
  }

  /**
   * 保存产品规格信息
   *
   * @param info 产品规格信息
   */
  private void storeSpec(List<BackstageSpecDataVO> info, Integer specValue, Integer goodsId) {
    // 获取数据库的集合
    List<HiolabsProduct> dbProducts =
        productService.list(
            Wrappers.<HiolabsProduct>lambdaQuery()
                .eq(HiolabsProduct::getGoodsId, goodsId)
                .eq(HiolabsProduct::getIsDelete, 0));
    for (BackstageSpecDataVO specDataVO : info) {
      HiolabsGoodsSpecification goodsSpecification = new HiolabsGoodsSpecification();
      if (Objects.equals(specDataVO.getId(), null)) {
        // 新数据
        goodsSpecification.setSpecificationId(specValue);
        goodsSpecification.setGoodsId(goodsId);
        goodsSpecification.setValue(specDataVO.getValue());
        goodsSpecificationMapper.insert(goodsSpecification);
        specDataVO.setGoodsSpecificationIds(goodsSpecification.getId());
        specDataVO.setGoodsId(goodsId);
      } else {
        // 旧数据
        goodsSpecification.setId(specDataVO.getGoodsSpecificationIds());
        goodsSpecification.setSpecificationId(specValue);
        goodsSpecification.setGoodsId(goodsId);
        goodsSpecification.setValue(specDataVO.getValue());
        goodsSpecificationMapper.updateById(goodsSpecification);
      }
    }
    List<HiolabsProduct> products =
        HiolabsProductConverter.INSTANCE.convertBackstageDataToPoList(info);
    // 逻辑删除部分产品数据以及规格
    if (dbProducts.size() > products.size()) {
      List<HiolabsGoodsSpecification> goodsSpecificationIds = new ArrayList<>();
      List<HiolabsProduct> collect =
          dbProducts.stream()
              .filter(
                  product -> {
                    if (!products.stream()
                        .map(HiolabsProduct::getId)
                        .collect(Collectors.toList())
                        .contains(product.getId())) {
                      HiolabsGoodsSpecification goodsSpecification =
                          new HiolabsGoodsSpecification();
                      goodsSpecification.setId(
                          Integer.parseInt(product.getGoodsSpecificationIds()));
                      goodsSpecification.setIsDelete(1);
                      goodsSpecificationIds.add(goodsSpecification);
                      return true;
                    }
                    return false;
                  })
              .peek(product -> product.setIsDelete(true))
              .collect(Collectors.toList());
      productService.updateBatchById(collect);
      goodsSpecificationService.updateBatchById(goodsSpecificationIds);
    }
    productService.saveOrUpdateBatch(products);
  }
}
